#include "thread_test.h"

#include <assert.h>

#include <fstream>

#include "FileMgr.h"

Thread_test::Thread_test()
    : m_nFlushInterval(1000)
    , m_bNeedRun(true)

    , m_thread(&Thread_test::backWork, this)
    , m_mutex()
    , m_cond()
//    , m_thGuard(m_thread)

    , m_nBufferSize(2)
    , m_pCurrentBuffer(new Buffer())
    , m_pNextBuffer(new Buffer())
    , m_BufferPool()
{
    m_pCurrentBuffer->reserve(m_nBufferSize);
    m_pNextBuffer->reserve(m_nBufferSize);
    m_BufferPool.reserve(16);


    std::fstream file;
    file.open("test.txt", std::fstream::out | std::fstream::app);

    file << "liuyang" << std::endl;



}

void Thread_test::append(std::string str)
{
    std::lock_guard<std::mutex> lock(m_mutex);

    if (m_pCurrentBuffer->size() < m_nBufferSize)
    {
        m_pCurrentBuffer->push_back(str);//单个buff的填充，可直接用值传递，不用指针
    }
    else
    {
        m_BufferPool.push_back(std::move(m_pCurrentBuffer));//unique_ptr只能使用move移动

        if (m_pNextBuffer)
        {
            m_pCurrentBuffer = std::move(m_pNextBuffer);
        }
        else
        {
            //当大量数据涌入，buff不够，需要新申请内存,很少出现
            std::cout << "there have many log at short time" << std::endl;
            m_pCurrentBuffer.reset(new Buffer());
            m_pCurrentBuffer->reserve(m_nBufferSize);
        }

        m_pCurrentBuffer->push_back(str);
        m_cond.notify_all();
    }
}

void Thread_test::backWork()
{
    FileMgr file("log.txt");

    BufferPtr newBuffer1(new Buffer());
    BufferPtr newBuffer2(new Buffer());

    newBuffer1->reserve(m_nBufferSize);
    newBuffer2->reserve(m_nBufferSize);

    BufferPool buffersToWrite;//用于将前端日志池交换到Write,进行写入
    buffersToWrite.reserve(16);

//    std::cout << "Buffer size " << newBuffer1->size() << buffersToWrite.size() << std::endl;

    while (m_bNeedRun)
    {
//        Sleep(1000);


//        std::unique_lock<std::mutex> lock(m_mutex);
//        m_cond.wait(lock, [&](){return !m_BufferPool.empty();});

        //上面两行等价与下面这个
//        while (m_BufferPool.empty())//缓存池为空时继续wait
//        {
//            std::unique_lock<std::mutex> lock(m_mutex);
//            m_cond.wait(lock);
//        }

        //转移所有日志到后端
        {
            std::unique_lock<std::mutex> lock(m_mutex);
            if (m_BufferPool.empty())
            {
                std::cout << "backWork sleep" << std::endl;

                m_cond.wait_for(lock, std::chrono::milliseconds(m_nFlushInterval));

                std::cout << "backWork wakeup" << std::endl;
            }

            m_BufferPool.push_back(std::move(m_pCurrentBuffer));
            m_pCurrentBuffer = std::move(newBuffer1);
            buffersToWrite.swap(m_BufferPool);

            if (!m_pNextBuffer)
            {
                std::cout << "backWork m_pNextBuffer is null" << std::endl;
                m_pNextBuffer = std::move(newBuffer2);
            }
        }//退出临界区，前端可继续写日志


        //处理极端情况，直接丢掉过量的日志池
        if (buffersToWrite.size() > 25)
        {
            buffersToWrite.erase(buffersToWrite.begin() + 2, buffersToWrite.end());
        }



        //日志写入磁盘类
//        for (const auto& buffer : buffersToWrite)
        for (const auto& buffer : buffersToWrite)
        {
//            std::cout << "current buffer size" << buffer->size() << std::endl;

            file.append(buffer);
        }



        //日志池中最多保留两个buffer
        if (buffersToWrite.size() > 2)
        {
            buffersToWrite.resize(2);
        }

        //为后端buffer填充
        if (!newBuffer1)
        {
            assert(!buffersToWrite.empty());
            newBuffer1 = std::move(buffersToWrite.back());
            buffersToWrite.pop_back();
            newBuffer1->clear();
        }

        if (!newBuffer2)
        {
            assert(!buffersToWrite.empty());
            newBuffer2 = std::move(buffersToWrite.back());
            buffersToWrite.pop_back();
            newBuffer2->clear();
        }


        //清空后端日志池
        buffersToWrite.clear();

        //磁盘类刷盘数据到硬盘




    }
    //磁盘类刷盘数据到硬盘

    std::cout << "thread func end" << std::endl;
}
